package com.lincoln.system.app.api;

import com.lincoln.bean.ApiCode;
import com.lincoln.bean.ApiCodeException;
import com.lincoln.bean.BaseApi;
import com.lincoln.bean.SpringBeanFactoryUtils;
import com.lincoln.entity.permission.DbPermission;
import com.lincoln.entity.permission.DbUserPermission;
import com.lincoln.entity.permission.UserPermissionTypeEnum;
import com.lincoln.entity.role.DbRole;
import com.lincoln.entity.user.DbUser;
import com.lincoln.service.PermissionService;
import com.lincoln.service.RoleService;
import com.lincoln.service.UserPermissionService;
import com.lincoln.service.UserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/system/permission")
@CrossOrigin
public class PermissionApi extends BaseApi {
    @Autowired
    PermissionService permissionService;
    @Autowired
    RoleService roleService;
    @Autowired
    UserService userService;
    @Autowired
    UserPermissionService userPermissionService;

    @GetMapping("/list")
    @PreAuthorize("hasAuthority('role_admin')")
    public ApiCode list(Integer pageNo, Integer pageSize, String name) {
        if (pageNo == null) {
            pageNo = 0;
        }
        if (pageSize == null) {
            pageSize = 10;
        }
        PageRequest pageRequest = permissionService.buildPageRequest(pageNo, pageSize, Sort.Order.desc("createTime"));
        Map<String, Object> params = new HashMap<>();
        if (StringUtils.isNotEmpty(name)) {
            params.put("name", name);
        }
        Page<DbPermission> page = permissionService.findPage(pageRequest, params);
        return ApiCode.build(page);
    }

    @GetMapping("/{idOrName}")
    @PreAuthorize("hasAuthority('role_admin')")
    public ApiCode info(@PathVariable String idOrName) throws Exception {
        if (StringUtils.isEmpty(idOrName)) {
            throw new ApiCodeException(ApiCode.PARAME_NEED);
        }
        DbPermission permission = permissionService.findByIdOrName(idOrName);
        if (permission == null) {
            throw new ApiCodeException(ApiCode.build(ApiCode.FAIL, "权限不存在!"));
        }
        return ApiCode.build(permission);
    }

    @PutMapping("/add")
    @PreAuthorize("hasAuthority('role_admin')")
    public ApiCode add(String permissions) throws Exception {
        if (StringUtils.isEmpty(permissions)) {
            return ApiCode.build(ApiCode.FAIL, "permissions can not be null!");
        }
        String[] names = permissions.split(",");
        permissionService.savePermissions(names);
        return ApiCode.findCode(ApiCode.SUCCESS);
    }

    @PostMapping("/{id}")
    @PreAuthorize("hasAuthority('role_admin')")
    public ApiCode edit(@PathVariable Long id, String name) throws Exception {
        if (id == null) {
            throw new ApiCodeException(ApiCode.PARAME_NEED);
        }
        if (StringUtils.isEmpty(name)) {
            throw new ApiCodeException(ApiCode.PARAME_NEED);
        }
        DbPermission permission = permissionService.findById(id);
        if (permission == null) {
            throw new ApiCodeException(ApiCode.ENTITY_NONE);
        }
        if (StringUtils.isNotEmpty(name)) {
            permission.setName(name);
        }
        permissionService.save(permission);
        return ApiCode.findCode(ApiCode.SUCCESS);
    }

    /**
     * 查询等级所含有的权限
     *
     * @param idOrName
     * @return
     * @throws ApiCodeException
     */
    @GetMapping("/role/{idOrName}")
    @PreAuthorize("hasAuthority('role_admin')")
    public ApiCode rolePermission(@PathVariable String idOrName) throws ApiCodeException {
        DbRole role = roleService.findByIdOrName(idOrName);
        if (role == null) {
            throw new ApiCodeException(ApiCode.findCode(ApiCode.ROLE_NONE));
        }
        return ApiCode.build(role.getPermissions());
    }

    /**
     * 获取用户所有的权限(经过黑白名单过滤后)
     *
     * @param idOrName
     * @return
     * @throws ApiCodeException
     */
    @GetMapping("/user/{idOrName}")
    @PreAuthorize("hasAuthority('role_admin')")
    public ApiCode userPermission(@PathVariable String idOrName) throws ApiCodeException {
        DbUser user = userService.findByIdOrName(idOrName);
        if (user == null) {
            throw new ApiCodeException(ApiCode.findCode(ApiCode.USER_NONE));
        }
        List<DbPermission> result = userService.findPermissions(idOrName);
        return ApiCode.build(result);
    }

    /**
     * 修改用户权限(在这里分出白名单黑名单)
     *
     * @param idOrName
     * @param permissionIds 权限id,","分割
     * @return
     * @throws ApiCodeException
     */
    @PostMapping("/user/{idOrName}")
    @PreAuthorize("hasAuthority('role_admin')")
    public ApiCode editUserPermission(@PathVariable String idOrName, String permissionIds) throws ApiCodeException {
        DbUser user = userService.findByIdOrName(idOrName);
        if (user == null) {
            throw new ApiCodeException(ApiCode.findCode(ApiCode.USER_NONE));
        }
        List<DbPermission> permissions = permissionService.findByIds(permissionIds);
        if (permissions == null || permissions.size() <= 0) {
            throw new ApiCodeException(ApiCode.build(ApiCode.PERMISSION_NONE));
        }
        List<DbPermission> rolePermissions = user.getRole().getPermissions();
        List<DbPermission> whites = new ArrayList<>();
        List<DbPermission> blacks = new ArrayList<>();
        for (DbPermission permission : permissions) {
            if (!rolePermissions.contains(permission)) {//等级中不存在的权限即是白名单
                whites.add(permission);
            }
        }
        for (DbPermission permission : rolePermissions) {
            if (!permissions.contains(permission)) {//结果中不存在的等级权限即是黑名单
                blacks.add(permission);
            }
        }
        /**
         * 保存白名单
         */
        userPermissionService.removeWhite(user.getId());
        for (DbPermission white : whites) {
            DbUserPermission userPermission = new DbUserPermission();
            userPermission.setPermission(white);
            userPermission.setUser(user);
            userPermission.setPermissionType(UserPermissionTypeEnum.WHITE);
            userPermissionService.save(userPermission);
        }
        /**
         * 保存黑名单
         */
        userPermissionService.removeBlack(user.getId());
        for (DbPermission black : blacks) {
            DbUserPermission userPermission = new DbUserPermission();
            userPermission.setPermission(black);
            userPermission.setUser(user);
            userPermission.setPermissionType(UserPermissionTypeEnum.BLACK);
            userPermissionService.save(userPermission);
        }
        return ApiCode.findCode(ApiCode.SUCCESS);
    }
}
